package gweb

import (
	"context"
	"errors"
	"fmt"
	"github.com/tidwall/gjson"
	"go.uber.org/zap"
	"go.uber.org/zap/zapcore"
	"gopkg.in/natefinch/lumberjack.v2"
	"os"
)

var (
	logger *zap.Logger
)

const (
	LoggerKey = "zapLogger"
)

func initLog() {
	if viperConfig.Log == nil {
		fmt.Println("log config is not found")
		return
	}
	if len(viperConfig.Log) == 0 {
		fmt.Println("log config is empty")
		return
	}
	var cores []zapcore.Core
	for _, v := range viperConfig.Log {
		if v.Enable {
			if core, e := initLogByConfig(v); e != nil {
				fmt.Printf("log type:%s init err:%s\r\n", v.Type, e.Error())
			} else {
				cores = append(cores, core)
			}
		}
	}
	if len(cores) > 0 {
		logger = zap.New(
			zapcore.NewTee(cores...),
			zap.AddCaller(),
			zap.AddStacktrace(zap.ErrorLevel), // Error 及以上自动记录堆栈
		)
	} else {
		logger, _ = zap.NewDevelopment()
	}
}

func initLogByConfig(logConfig LogConfig) (zapcore.Core, error) {
	var writeSyncer zapcore.WriteSyncer
	var encoder zapcore.Encoder
	level, err := zapcore.ParseLevel(logConfig.Level)
	if err != nil {
		return nil, err
	}
	if logConfig.Type == "console" {
		writeSyncer = zapcore.AddSync(os.Stdout)
		encoder = zapcore.NewConsoleEncoder(zap.NewDevelopmentEncoderConfig())
	} else if logConfig.Type == "file" {
		option := gjson.Parse(logConfig.Option)
		var _filename string
		if option.Get("filename").Exists() {
			_filename = option.Get("filename").String()
		} else {
			_filename = "gweb.log"
		}
		var _maxSize int
		if option.Get("maxSize").Exists() {
			_maxSize = int(option.Get("maxSize").Int())
		} else {
			_maxSize = 10
		}
		var _maxBackups int
		if option.Get("maxBackups").Exists() {
			_maxBackups = int(option.Get("maxBackups").Int())
		} else {
			_maxBackups = 5
		}
		var _maxAge int
		if option.Get("maxAge").Exists() {
			_maxAge = int(option.Get("maxAge").Int())
		} else {
			_maxAge = 30
		}
		writeSyncer = zapcore.AddSync(&lumberjack.Logger{
			Filename:   _filename,
			MaxSize:    _maxSize,
			MaxBackups: _maxBackups,
			MaxAge:     _maxAge,
			Compress:   option.Get("compress").Bool(),
		})
		encoder = zapcore.NewJSONEncoder(zap.NewProductionEncoderConfig())
	} else {
		return nil, errors.New("log type not support")
	}
	levelEnabler := zap.LevelEnablerFunc(func(lvl zapcore.Level) bool {
		return lvl >= level
	})
	return zapcore.NewCore(encoder, writeSyncer, levelEnabler), nil
}

func GetLog(ctx context.Context) *zap.Logger {
	if _logger, ok := ctx.Value(LoggerKey).(*zap.Logger); ok {
		return _logger
	}
	return logger
}
